package com.zrkizzy.module.content.service.article;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zrkizzy.common.core.domain.response.OptionsVO;
import com.zrkizzy.common.core.utils.IdUtil;
import com.zrkizzy.common.models.domain.blog.tag.ArticleTags;
import com.zrkizzy.content.facade.service.article.IArticleTagsService;
import com.zrkizzy.module.content.exception.BlogErrorCode;
import com.zrkizzy.module.content.mapper.article.ArticleTagsMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * 文章标签关联业务逻辑接口实现类
 *
 * @author zhangrongkang
 * @since 2023/10/7
 */
@Slf4j
@Service
public class ArticleTagsServiceImpl implements IArticleTagsService {

    @Autowired
    private IdUtil idUtil;

    @Autowired
    private ArticleTagsMapper articleTagsMapper;

    /**
     * 获取指定文章对应标签
     *
     * @param articleId 文章ID
     * @return 文章标签集合
     */
    @Override
    public List<ArticleTags> listTagsByArticleId(Long articleId) {
        // 获取指定内容
        return articleTagsMapper.listTagsByArticleId(articleId);
    }

    /**
     * 为指定文章添加标签
     *
     * @param tagIds    标签集合
     * @param articleId 文章ID
     * @return 是否添加成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insert(List<Long> tagIds, Long articleId) {
        // 校验ID集合
        checkTagIds(tagIds);
        return save(tagIds, articleId);
    }

    /**
     * 根据文章ID获取对应标签
     *
     * @param articleId 文章ID
     * @return 文章对应选择的标签
     */
    @Override
    public List<OptionsVO> listTagOptionsByArticleId(Long articleId) {
        return articleTagsMapper.listTagOptionsByArticleId(articleId);
    }

    /**
     * 根据文章ID获取选择的标签ID集合
     *
     * @param articleId 文章ID
     * @return 文章对应选择的标签ID
     */
    @Override
    public List<String> listTagIdsByArticleId(Long articleId) {
        // 定义返回结果
        List<String> result = new ArrayList<>();
        // 获取标签选项
        List<OptionsVO> list = listTagOptionsByArticleId(articleId);
        for (OptionsVO optionsVO : list) {
            result.add(String.valueOf(optionsVO.getValue()));
        }
        return result;
    }

    /**
     * 更新文章标签数据
     *
     * @param tagIds    标签集合
     * @param articleId 文章ID
     * @return 是否更新成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean update(List<Long> tagIds, Long articleId) {
        // 校验ID集合
        checkTagIds(tagIds);
        // 先删除当前文章所有标签
        if (deleteByArticleId(articleId)) {
            return save(tagIds, articleId);
        }
        return Boolean.FALSE;
    }

    /**
     * 保存文章标签对象到数据库中
     *
     * @param tagIds 文章标签ID
     * @param articleId 文章ID
     * @return 是否保存成功
     */
    private Boolean save(List<Long> tagIds, Long articleId) {
        List<ArticleTags> list = new ArrayList<>();
        // 封装当前对象
        for (Long tagId : tagIds) {
            list.add(ArticleTags.builder().id(idUtil.nextId()).articleId(articleId).tagId(tagId).build());
        }
        // 关联当前所有标签到文章，返回受影响的行数与传来的标签ID集合大小对比
        return tagIds.size() == articleTagsMapper.batchInsert(list);
    }

    /**
     * 删除指定文章对应标签
     *
     * @param articleId 文章ID
     * @return 是否删除成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteByArticleId(Long articleId) {
        // 定义查询条件
        QueryWrapper<ArticleTags> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("article_id", articleId);
        // 查询数据库中当前文章对应标签的数量，Long类型在和int类型比较时会自动调用intValue方法转为int进行比较
        Long count = articleTagsMapper.selectCount(queryWrapper);
        // 比较受影响行数来判断是否删除成功
        return articleTagsMapper.delete(queryWrapper) == count;
    }

    /**
     * 校验标签ID集合是否合法
     *
     * @param tagIds 标签ID集合
     */
    private void checkTagIds(List<Long> tagIds) {
        // 越界判断
        if (CollectionUtils.isEmpty(tagIds)) {
            throw BlogErrorCode.TAGS_NOT_EMPTY.exception();
        }
    }
}
